package com.juyu.miliao.scheduler.config;

import com.juyu.miliao.common.dataSource.*;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;

import com.juyu.miliao.common.dataSource.key.DataSourceKey;
import com.juyu.miliao.common.dataSource.key.DataSourceKeyEvaluator;
import com.juyu.miliao.common.dataSource.tool.distributeOperate.DistributeOperateAspect;
import com.juyu.miliao.common.dataSource.tool.distributeOperate.DistributeResultHandlers;
import com.juyu.miliao.common.dataSource.tool.operate.OperateAspect;
import com.juyu.miliao.scheduler.dao.redis.UserRedisDao;

import javax.sql.DataSource;

@Configuration
public class DatabaseConfig {
	@Autowired
	private ResourcePatternResolver resourcePatternResolver;
	@Autowired
	private UserRedisDao userRedisDao;

	@Bean
	public DataSourceKey dataSourceKey(){
		return new DataSourceKey();
	}
	
	@Bean
	public DataSourceKeyEvaluator dataSourceKeyEvaluator(){
		return new GlobalDataSourceKeyEvaluator(userRedisDao);
	}
	
	@Bean
	public OperateAspect operateAspect(DataSourceKey dataSourceKey, DataSourceKeyEvaluator dataSourceKeyEvaluator){
		return new OperateAspect(dataSourceKey, dataSourceKeyEvaluator);
	}
	
	@Bean
	@ConfigurationProperties("app.multiple-datasource")
	public MultipleDataSourceConfig multipleDataSourceConfig() {
		return new MultipleDataSourceConfig();
	}
	
	@Bean
	public MultipleDataSourceParser multipleDataSourceParser(MultipleDataSourceConfig multipleDataSourceConfig){
		return MultipleDataSourceParser.builder().setMultipleDataSourceConfig(multipleDataSourceConfig).build();
	}
	
	@Bean
	public DistributeResultHandlers distributeResultHandlers(){
		return new GlobalDistributeResultHandlers();
	}
	
	@Bean
	public DistributeOperateAspect distributeOperateAspect(DataSourceKey dataSourceKey, DataSourceKeyEvaluator dataSourceKeyEvaluator, 
			MultipleDataSourceParser multipleDataSourceParser, DistributeResultHandlers distributeResultHandlers){
		return new DistributeOperateAspect(dataSourceKey, dataSourceKeyEvaluator, multipleDataSourceParser, distributeResultHandlers);
	}
	
	@Bean
	public MultipleDataSource dataSource(MultipleDataSourceParser multipleDataSourceParser, DataSourceKey dataSourceKey){
		MultipleDataSource multipleDataSource = new MultipleDataSource(dataSourceKey);
		multipleDataSource.setDefaultTargetDataSource(multipleDataSourceParser.getDefaultDataSource());
		multipleDataSource.setLenientFallback(false);
		multipleDataSource.setTargetDataSources(multipleDataSourceParser.getDataSourceMap());
		return multipleDataSource;
	}

	private SqlSessionFactory createSqlSessionFactory(Object key, Object dataSource) {
		try{
			SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
			sqlSessionFactoryBean.setDataSource((DataSource) dataSource);
			Resource[] resources = resourcePatternResolver
					.getResources("classpath*:com/juyu/miliao/scheduler/dao/mysql/*.xml");
			sqlSessionFactoryBean.setMapperLocations(resources);
			org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
			configuration.setMapUnderscoreToCamelCase(true);
			sqlSessionFactoryBean.setConfiguration(configuration);
			return sqlSessionFactoryBean.getObject();
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}

	@Bean
	public SqlSession sqlSession(DataSourceKey dataSourceKey, MultipleDataSourceParser multipleDataSourceParser) throws Exception {
		MultipleSqlSessionFactoryParser parser = MultipleSqlSessionFactoryParser.builder()
				.setMultipleDataSourceParser(multipleDataSourceParser)
				.setSqlSessionFactoryCreater(this::createSqlSessionFactory)
				.build();
		return new MutipleSqlSessionTemplate(dataSourceKey, parser.getDefaultSqlSessionFactory(), parser.getSqlSessionFactoryMap());
	}
	
}
